/******************************************************************************
 * Author:      671643387
 * Created:     2016/9/27
 *****************************************************************************/

function Player(uid) {
    this.uid = uid;
    this.user = {};

    this.dirty = {};                    // 本次操作脏数据
    this.allDirty = {};                 // 累计的脏数据
    this.saveCount = 0;                 // 数据库存盘计数
    this.saveError = false;             // 是否出现数据库写入错误
}
Player.create = function(uid){
    var now = Date.getStamp();

    var initUser = {
        '_id': uid,
        'lock': 0,                                 // 并发锁, 0空闲 >0解锁时间(单位s)
        'ai': 1,                                   // 自增长ID,用于编号系统
        'info': {                                  // 基本信息
            'name'    : '',                        // 玩家名字
            'headpic' : 0,                         // 玩家头像
        },

        'status': {                                // 基础数据
            'card'    : 10,                        // 房卡数量
        },

        'marks': {                                 // 标志
            'room'     : 0,                        // 玩家当前所在房间
        },

        'reports': [],                              // 战报

    };
    return initUser;
};
Player.prototype = {
    init: function(fields, callback){
        if (fields && (typeof(fields) == 'object') &&
            Object.getOwnPropertyNames(fields).length > 0) {
            // 加载玩家部分数据
            fields['ai'] = 1;
        }

        var player = this;

        // 读取玩家数据
        gDBUser.findOne({_id : player.uid}, fields, function(err, doc) {
            if (!doc) {
                if (err) {
                    callback && callback(false);
                } else {
                    //创建新用户
                    player.user = Player.create(player.uid);

                    gDBUser.insertOne(player.user, function(err, result) {
                        if (err) {
                            callback && callback(false);
                        } else {
                            callback && callback(true);
                        }
                    });
                }
            } else {
                player.user = doc;
                callback && callback(true);
            }
        });
    },

    arrangeDirty : function(dirty) {
        var arrangedDirty = {};

        for (var item in dirty) {
            var dirtyType = dirty[item];

            var needRemove = [];
            var addNew = true;
            var levels = item.split('.');
            for (var eitem in arrangedDirty) {
                var elevels = eitem.split('.');
                if (elevels.length == levels.length) continue;
                var minLen = Math.min(elevels.length, levels.length);

                var isTree = true;
                for (var i = 0; i < minLen; i++) {
                    if (elevels[i] != levels[i]) {
                        isTree = false;
                        break;
                    }
                }

                if (!isTree) continue;

                if (elevels.length < levels.length) {
                    // 更低级别的变更,抛弃
                    addNew = false;
                    break;
                } else {
                    // 更高级别的变更
                    needRemove.push(eitem);
                }
            }

            needRemove.forEach(function(removeItem) {
                delete arrangedDirty[removeItem];
            });

            if (addNew) {
                arrangedDirty[item] = dirtyType;
            }
        }
        return arrangedDirty;
    },

    save: function(force, callback) {
        // 合并写入
        var haveDirty = false;
        for (var key in this.dirty) {
            haveDirty = true;
            this.allDirty[key] = this.dirty[key];
        }

        this.dirty = {};

        if (haveDirty) {
            this.saveCount += 1;
        }

        // TODO
        if ((!force && this.saveCount < 1) || (Object.keys(this.allDirty).length == 0)) {
            // 1次数据库操作必写入
            callback && callback(true);
            return;
        }

        var updates = {$set: {}, $unset: {}};
        var arrangedDirty = this.arrangeDirty(this.allDirty);
        for (var item in arrangedDirty) {
            var remove = arrangedDirty[item];
            if (remove) {
                updates['$unset'][item] = 1;
            } else {
                var obj = this.user;
                var args = item.split(".");
                var ok = true;
                for (var i = 0; i < args.length; i++) {
                    if (typeof(obj) != 'object') {
                        // 未找到
                        ok = false;
                        break;
                    }
                    obj = obj[args[i]];
                }

                if (ok && obj != undefined && obj != NaN && obj != null) {
                    updates['$set'][item] = obj;
                } else {
                    ERROR('invalid save: ' + item);
                }
            }
        }

        this.allDirty = {};
        this.saveCount = 0;

        var toUpdate = 2;

        if (Object.keys(updates['$unset']).length == 0) {
            delete updates['$unset'];
            toUpdate--;
        }

        if (Object.keys(updates['$set']).length == 0) {
            delete updates['$set'];
            toUpdate--;
        }

        if(toUpdate) {
            gDBUser.update({_id : this.uid}, updates, function(err, result) {
                if (err) {
                    ERROR(util.format('%d SAVE %j %j', this.uid, updates, err));
                    this.saveError = true;
                    callback && callback(false);
                } else {
                    callback && callback(true);
                }
            } .bind(this));
        }
    },

    markDirty : function(item) {
        this.dirty[item] = 0;
    },

    addResource: function(name, value) {
        var user = this.user;
        if (!user.status.hasOwnProperty(name)) {
            user.status[name] = 0;
        }

        if ((value < 0) && ((user.status[name] + value) < 0)) {
            return false;
        }

        user.status[name] += +value;
        this.markDirty('status.' + name);
        return true;
    },

    checkResource: function(name, value) {
        var user = this.user;
        if (!user.status.hasOwnProperty(name)) {
            user.status[name] = 0;
        }
        return (user.status[name] >= value) ? true : false;
    },

    saveReport: function(report) {
        var user = this.user;
        user.reports.push(report);
        if (user.reports.length > 30) {
            user.reports.splice(0, user.reports.length - 30);
        }
        this.markDirty('reports');
    },
};

///////////////////////////////////////////////////////////////////////////////
// 玩家管理器
function PlayerManager() {
    this.playerCache = {};
}
PlayerManager.prototype = {
    get: function(uid, callback) {
        if (this.playerCache.hasOwnProperty(uid)) {
            callback(this.playerCache[uid]);
        } else {
            this.load(uid, callback);
        }
    },
    load: function(uid, callback) {
        var player = new Player(uid);
        player.init({}, function(succ) {
            if (succ) {
                this.playerCache[uid] = player;
                callback && callback(player);
            } else {
                callback && callback(null);
            }
        } .bind(this));
        player.save(true);
    }
};
exports.PlayerManger = PlayerManager;